
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Using Custom Events</title>

<style type="text/css">
/*margin and padding on body element
  can introduce errors in determining
  element position and are not recommended;
  we turn them off as a foundation for YUI
  CSS treatments. */
body {
	margin:0;
	padding:0;
}
</style>

<link type="text/css" rel="stylesheet" href="../../build/cssfonts/fonts-min.css" />
<script type="text/javascript" src="../../build/yui/yui-min.js"></script>


<!--begin custom header content for this example-->
<style type="text/css">
	#fire {margin:1em;}
	#log {
		border:1px dotted #999999; background-color:#FFFFFF;
	}
	#log li {padding:5px;}
	#log li highlight {color:#993300;}
</style>
<!--end custom header content for this example-->

</head>

<body class="yui3-skin-sam  yui-skin-sam">

<h1>Using Custom Events</h1>

<div class="exampleIntro">
	<p>The Custom Event framework is one of the principle communication mechanisms
in YUI.  An object can be augmented with <code>EventTarget</code>, enabling it
to be both a host and a target for Custom Events.  Custom Events fire from
their host and optionally bubble up to one or more targets.  This allows you to
make the interesting moments of your applications broadly available within a
module, within a set of modules, or throughout a complex interface populated
with rich elements.</p>

<p>In this example, a simple Custom Event is illustrated:
<code>testEvent</code>.  This Custom Event is hosted on a Publisher object and
bubbles up to a BubbleTarget object.</p>

<p><img src="assets/ce-example.gif" alt="An
illustration of the relationship between the Custom Event, its host, and its
Bubble Target."></p>

<p>Custom Events, like DOM events, can be stopped
(<code>stopPropagation</code>) and their default behavior can be suppressed
(<code>preventDefault</code>).</p>
			
</div>

<!--BEGIN SOURCE CODE FOR EXAMPLE =============================== -->

<button id="fire" value="Fire">Fire publisher:testEvent</button> <br />
<input type="checkbox" id="stopPropagation"> <label for="stopPropagation">Stop Propagation (testEvent won't bubble to the BubbleTarget.)</label><br />
<input type="checkbox" id="preventDefault"> <label for="preventDefault">Prevent Default (testEvent's defaultFn won't fire.)</label>

<ol id="log">
	<li>Custom Event log messages will appear here.</li>
</ol>

<script language="javascript">

//Create a YUI instance:
YUI({ filter: 'raw' }).use("node", "event-custom-complex",

function(Y) {

    //Shortcut for our logging div:
    var logger = Y.one("#log");

    //Our BubbleTarget object is an object to which our Custom Event
    //will be allowed to bubble.  It needs itself to be an EventTarget,
    //so we'll use augment to make it an EventTarget:
    var BubbleTarget = function() {
        Y.log("Host constructor executed.", "info", "example");
    }
    //Augment BubbleTarget to make it an EventTarget:
    Y.augment(BubbleTarget, Y.EventTarget);

    //Create an instance of BubbleTarget:
    var bubbleTarget = new BubbleTarget();

    //Now we'll subscribe to the "publisher:testEvent" -- note
    //that we can do this even before this event is published:
    bubbleTarget.subscribe("publisher:testEvent", function(e) {
        Y.log("publisher:testEvent fired on the BubbleTarget object.", "info", "example");
    });

    //Now we'll create the constructor for the Publisher, which 
    //is the direct host of our Custom Event.  It will also be an
    //EventTarget, so we'll extend it as well:
    var Publisher = function(bubbleTarget) {

        //We'll specify now that Custom Events hosted by Publisher
        //should bubble to the bubbleTarget instance passed into the
        //the Publisher's constructor:
        this.addTarget(bubbleTarget);

        //Here we publish the Custom Event.  Note that it's not
        //necessary to publish the event at all if you don't have
        //options you wish to configure -- firing the event or 
        //subscribing to it will create it on the fly if necessary:
        this.publish("publisher:testEvent",
            {
                emitFacade: true,
                //the defaultFn is what you want to have happen
                //by default when no subscriber calls preventDefault:
                defaultFn: function() {
                    Y.log("defaultFn: publisher:testEvent's defaultFn executed.", "info", "example");
                },
                //You can prevent the default function from firing by
                //calling preventDefault from a listener (if the Custom
                //Event's preventable option is set to true, as it is by
                //default).  If the default is prevented, the preventedFn
                //is called, allowing you to respond if necessary.
                preventedFn: function() {
                    Y.log("preventedFn: A subscriber to publisher:testEvent called preventDefault().", "info", "example");			
                },
                //The stoppedFn is called if a subscriber calls stopPropagation or
                //stopImmediatePropagation:
                stoppedFn: function() {
                    Y.log("stoppedFn: A subscriber to publisher:testEvent called stopPropagation().", "info", "example");
                }
            }
        );
        Y.log("Publisher constructor executed.");
    }
    //Augment Publisher to make it an EventTarget:
    Y.augment(Publisher, Y.EventTarget);

    //Create a Publisher instance:
    var p = new Publisher(bubbleTarget);

    //We've already subscribed to the event on the bubbleTarget, but
    //we can also subscribe to it here on the Publisher instance.
    //We'll see the event fire here before it bubbles up to the 
    //bubbleTarget:
    p.on("publisher:testEvent", function(e) {
        Y.log("publisher:testEvent subscriber fired on the publisher object.", "info", "example");
        if(Y.one("#stopPropagation").get("checked")) {
            //we will stopPropagation on the Custom Event, preventing
            //it from bubbling to the bubbleTarget:
            e.stopPropagation();
        }
        
        if(Y.one("#preventDefault").get("checked")) {
            //we will preventDefault on the Custom Event, preventing
            //the testEvent's defaultFn from firing:
            e.preventDefault();
        }
    });

    //We can tie our testEvent to an interface gesture -- the click of a
    //button, for example.
    Y.on("click", function(e) {
        //clear out the logger:
        logger.empty();
        p.fire("publisher:testEvent");
    }, "#fire");

    //write out log messages to the page:
    Y.on("yui:log", function(e) {
        logger.append("<li>" + e.msg + "</li>");
    });

});
</script>

<!--END SOURCE CODE FOR EXAMPLE =============================== -->

</body>
</html>
